package com.tplhk.redis.lock.redisson.service;

import com.tplhk.redis.lock.redisson.dto.User;
import com.zengtengpeng.annotation.Lock;
import com.zengtengpeng.enums.LockModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class RedissonLockService {

    /**
     * attemptTimeout， lockWatchdogTimeout 的关系
     * <p>
     * 1. 当 attemptTimeout = -1 时
     * 1.1 当 lockWatchdogTimeout =-1 ，缓存时间为看门狗全局配置时间（默认30s),
     * 并启动看门狗 , 每间隔 1/3 时间会自动续期，续期时间为看门狗全局配置时间（默认30s)
     * 应用场景，所有线程都有执行的机会，只是等待时间的长短问题
     * 1.2 【不安全】当 lockWatchdogTimeout !=1 ，缓存时间为 lockWatchdogTimeout ,
     * 但不启动看门狗， 只有 lockWatchdogTimeout 时间结束才会续期，续期时间为 lockWatchdogTimeout
     * 要强调的是，此时续期好像会删除key，会让等待中的线程也拿到锁，出现多个线程同时执行
     * 2. 当 attemptTimeout ！=1 时， 线程等待获取锁时间，超时就报 "获取锁失败"。对于得到锁的线程来说：
     * 2.1 当 lockWatchdogTimeout =-1 ，缓存时间为看门狗全局配置时间（默认30s),
     * 并启动看门狗 , 每间隔 1/3 时间会自动续期，续期时间为看门狗全局配置时间（默认30s)
     * 应用场景，超时线程会放弃执行机会
     * 2.2【不安全】当 lockWatchdogTimeout !=1 ，缓存时间为 lockWatchdogTimeout ,
     * 但不启动看门狗， lockWatchdogTimeout 结束后自动删除缓存key.
     * 这种情况是不安全的，因为该线程结束后，由于找不到 key 会抛异常
     * <p>
     * 总结: 建议使用看门狗，即  lockWatchdogTimeout 传 -1 ，而缓存时间使用看门狗全局配置时间
     *
     * @param user
     * @param threadName
     * @return
     * @throws InterruptedException
     */

//     lockWatchdogTimeout = -1 , 缓存时间使用看门狗时间全局配置时间(30s) , 并启动看门狗进程续期。 attemptTimeout 表示一直等待 10 秒,超时报 "获取锁失败"
//    @Lock(keys = "#user.username",keyConstant = "常量", attemptTimeout = 10*1000, lockWatchdogTimeout = -1, lockModel = LockModel.REDLOCK)
    // lockWatchdogTimeout = -1 , 缓存时间使用看门狗时间全局配置时间(30s) , 并启动看门狗进程续期。 attemptTimeout =-1 表示一直等待
//    @Lock(keys = "#user.username",keyConstant = "常量",  attemptTimeout = -1, lockWatchdogTimeout = -1,)
    // lockWatchdogTimeout 不传, 缓存时间使用看门狗时间全局配置时间(30s) 但是不会启动看门狗进程续期，30s 结束后才会续期 30s。 attemptTimeout =-1 表示一直等待,
//    @Lock(keys = "#user.username",keyConstant = "常量", attemptTimeout = -1)
//    // 缓存时间 20 秒,  attemptTimeout =-1 表示一直等待
//    @Lock(keys = "#user.username",keyConstant = "常量", attemptTimeout = -1 , lockWatchdogTimeout = 20*1000)
//    // 缓存时间 10 秒,  attemptTimeout =10 表示等待 10s .另外，当缓存时间结束后，不会再续期，即 key 自动删除
    @Lock(keys = "#user.username", keyConstant = "常量", attemptTimeout = 10 * 1000, lockWatchdogTimeout = 10 * 1000)
    public String test(User user, String threadName) throws InterruptedException {
        log.info("线程 [{}] 进来了test", threadName);
        TimeUnit.SECONDS.sleep(25);
        log.info("线程 [{}] 出去了", threadName);
        return "test";
    }
}
